#include "node.h"
#include "table.h"
#include <cstdio>
#include <cstdlib>

tdf_node::tdf_node():   parent_table( NULL ),
                        parent( NULL ){}
tdf_node::tdf_node(string* str,tdf_content_table* parenttable,tdf_node* par):   parent_table( parenttable ),
                                                                                parent( par ){
    if( parent_table ){
        index = parent_table->nodesNT.addName(str);
    }
}
tdf_node::tdf_node(char* str,tdf_content_table* parenttable,tdf_node* par): parent_table( parenttable ),
                                                                            parent( par ){
    if( parent_table ){
        index = parent_table->nodesNT.addName(str);
    }
}
tdf_node::~tdf_node(){}

string tdf_node::getName(){
    if( !parent_table ) return "";
    return parent_table->nodesNT.getName(index);
}
string tdf_node::getPath(){
    if( parent ){
        string stackstr = parent->getPath()+"/"+getName();
        char buffer[30];
        unsigned int stacki = getNumber();
        if( stacki ){
            stackstr += '[';
            stackstr += itoa(stacki,buffer,10);
            stackstr += ']';
        }
        return stackstr;
    }
    return getName();
}
unsigned int tdf_node::getIndex(){
    return index;
}
unsigned int tdf_node::getNumber(){
    if( !parent ) return 0;
    tdf_node* stack = parent->getFirstChildNodeAs( index );
    unsigned int cnt = 0;
    do{
        if( stack == this ) return cnt;
        cnt++;
    }while((stack = parent->getNextChildNodeAs(stack)));
    return 0;
}

tdf_node* tdf_node::addChildNode(string* str){
    childNodes.push_back( tdf_node( str, parent_table, this ) );
    return getLastChildNode();
}
tdf_node* tdf_node::addChildNode(char* str){
    childNodes.push_back( tdf_node( str, parent_table, this ) );
    return getLastChildNode();
}

tdf_node* tdf_node::getParentNode(){
    return parent;
}

void tdf_node::exportNode(FILE* file){

    fwrite( &index, sizeof( unsigned int ), 1, file );
    fflush( file );

    value.exportVariant( file );

    unsigned int size = attrib.size();
    fwrite(&size, sizeof( unsigned int ), 1, file );
    fflush( file );
    for( vector<tdf_attribute>::iterator i = attrib.begin(); i < attrib.end(); i++ ){
        (*i).exportAttribute( file );
    }

    size = childNodes.size();
    fwrite(&size, sizeof( unsigned int ), 1, file );
    fflush( file );
    for( vector<tdf_node>::iterator i = childNodes.begin(); i < childNodes.end(); i++ ){
        (*i).exportNode( file );
    }

}

void tdf_node::importNode(FILE* file,tdf_content_table* ctt,tdf_node* nd){

    printf("  Start(%ld)\n",ftell(file));

    if( ctt ) parent_table = ctt;
    if( nd ) parent = nd;

    printf("  Clean(%ld)\n",ftell(file));
    childNodes.clear();
    attrib.clear();
    value.clear();

    printf("  Index(%ld)\n",ftell(file));
    fread( &index, sizeof(unsigned int), 1, file );

    printf("  Value(%ld)\n",ftell(file));
    value.importVariant(file);
    printf("%s\n",value.toString().c_str());

    unsigned int size;
    printf("  ASize(%ld)\n",ftell(file));
    fread(&size, sizeof(unsigned int), 1, file );
    printf("  Attribs(%ld)\n",ftell(file));
    for( unsigned int i = 0; i < size; i++ ){
        tdf_attribute stack(file, parent_table);
        attrib.push_back( tdf_attribute() );
        attrib.back().copy( &stack );
        printf("%s\n",attrib.back().value.toString().c_str());
    }

    printf("  ChildNodes(%ld)\n",ftell(file));
    fread(&size, sizeof(unsigned int), 1, file );
    for( unsigned int i = 0; i < size; i++ ){
        childNodes.push_back( tdf_node() );
        childNodes.back().importNode(file, parent_table, this );
    }

    printf("  End(%ld)\n",ftell(file));

}

void tdf_node::exportNodeXML(FILE* file, string cat){
    fprintf(file,"%s<%s",cat.c_str(),getName().c_str());
    for( vector<tdf_attribute>::iterator i = attrib.begin(); i < attrib.end(); i++ ){
        fprintf(file," %s=\"[T:%s]%s\"",(*i).getName().c_str(),variant::typeToShortString((*i).value.getType()),(*i).value.toString().c_str());
    }
    if( value.getType() == VAR_UNDEF && childNodes.size() == 0 ){
        fprintf(file,"/>\n");
        return;
    }
    fprintf(file,">\n");
    if( value.getType() != VAR_UNDEF ) fprintf(file,"%s\t%s\n",cat.c_str(),value.toString().c_str());
    for( vector<tdf_node>::iterator i = childNodes.begin(); i < childNodes.end(); i++ ){
        (*i).exportNodeXML(file,cat+"\t");
    }
    fprintf(file,"%s</%s>\n",cat.c_str(),getName().c_str());
}

bool tdf_node::getChildNodePosAs(tdf_node* needle,unsigned int* out){
    int cnt = 0;
    for(vector<tdf_node>::iterator i = childNodes.begin(); i < childNodes.end(); i++){
        if( &(*i) == needle ){
            *out = cnt;
            return true;
        }
        cnt++;
    }
    return false;
}
bool tdf_node::getChildNodePosAs(tdf_node* needle,vector<tdf_node>::iterator* it){
    for( *it = childNodes.begin(); *it < childNodes.end(); (*it)++ ){
        if( &(*(*it)) == needle ){
            return true;
        }
    }
    return false;
}
bool tdf_node::getChildNodePosAs(tdf_node* needle,vector<tdf_node>::reverse_iterator* it){
    for( *it = childNodes.rbegin(); *it < childNodes.rend(); (*it)++ ){
        if( &(*(*it)) == needle ){
            return true;
        }
    }
    return false;
}

bool tdf_node::getAttribPosAs(tdf_attribute* needle,unsigned int* out){
    int cnt = 0;
    for(vector<tdf_attribute>::iterator i = attrib.begin(); i < attrib.end(); i++){
        if( &(*i) == needle ){
            *out = cnt;
            return true;
        }
        cnt++;
    }
    return false;
}
bool tdf_node::getAttribPosAs(tdf_attribute* needle,vector<tdf_attribute>::iterator* it){
    for( *it = attrib.begin(); *it < attrib.end(); (*it)++ ){
        if( &(*(*it)) == needle ){
            return true;
        }
    }
    return false;
}
bool tdf_node::getAttribPosAs(tdf_attribute* needle,vector<tdf_attribute>::reverse_iterator* it){
    for( *it = attrib.rbegin(); *it < attrib.rend(); (*it)++ ){
        if( &(*(*it)) == needle ){
            return true;
        }
    }
    return false;
}

unsigned int tdf_node::countChildNode(){
    return childNodes.size();
}
tdf_node* tdf_node::getFirstChildNode(){
    if( !childNodes.size() ) return NULL;
    return &(*(childNodes.begin()));
}
tdf_node* tdf_node::getLastChildNode(){
    if( !childNodes.size() ) return NULL;
    return &(*(childNodes.rbegin()));
}
tdf_node* tdf_node::getNextChildNode(tdf_node* ref){
    if( !ref ) return NULL;
    vector<tdf_node>::iterator  i;
    if( !getChildNodePosAs(ref,&i) ) return NULL;
    i++;
    if( i >= childNodes.end() ) return NULL;
    return &(*i);
}
tdf_node* tdf_node::getPrevChildNode(tdf_node* ref){
    if( !ref ) return NULL;
    vector<tdf_node>::reverse_iterator  i;
    if( !getChildNodePosAs(ref,&i) ) return NULL;
    i++;
    if( i >= childNodes.rend() ) return NULL;
    return &(*i);
}
tdf_node* tdf_node::getChildNodeAt(unsigned int idx){
    return &(childNodes.at(idx));
}

unsigned int tdf_node::countChildNodeAs(unsigned int idx){
    unsigned int cnt = 0;
    for(vector<tdf_node>::iterator i = childNodes.begin(); i < childNodes.end(); i++ ){
        if( (*i).getIndex() == idx ) cnt++;
    }
    return cnt;
}
unsigned int tdf_node::countChildNodeAs(string* str){
    if( !parent_table ) return 0;
    unsigned int idx;
    if( !parent_table->nodesNT.findName(str,&idx) ) return 0;
    return countChildNodeAs( idx );
}
unsigned int tdf_node::countChildNodeAs(char* str){
    if( !parent_table ) return 0;
    unsigned int idx;
    if( !parent_table->nodesNT.findName(str,&idx) ) return 0;
    return countChildNodeAs( idx );
}

tdf_node* tdf_node::getFirstChildNodeAs(unsigned int idx){
    for(vector<tdf_node>::iterator i = childNodes.begin(); i < childNodes.end(); i++ ){
        if( (*i).getIndex() == idx ) return &(*i);
    }
    return NULL;
}
tdf_node* tdf_node::getFirstChildNodeAs(string* str){
    if( !parent_table ) return NULL;
    unsigned int idx;
    if( !parent_table->nodesNT.findName(str,&idx) ) return NULL;
    return getFirstChildNodeAs( idx );
}
tdf_node* tdf_node::getFirstChildNodeAs(char* str){
    if( !parent_table ) return NULL;
    unsigned int idx;
    if( !parent_table->nodesNT.findName(str,&idx) ) return NULL;
    return getFirstChildNodeAs( idx );
}

tdf_node* tdf_node::getLastChildNodeAs(unsigned int idx){
    for(vector<tdf_node>::reverse_iterator i = childNodes.rbegin(); i < childNodes.rend(); i++ ){
        if( (*i).getIndex() == idx ) return &(*i);
    }
    return NULL;
}
tdf_node* tdf_node::getLastChildNodeAs(string* str){
    if( !parent_table ) return NULL;
    unsigned int idx;
    if( !parent_table->nodesNT.findName(str,&idx) ) return NULL;
    return getLastChildNodeAs( idx );
}
tdf_node* tdf_node::getLastChildNodeAs(char* str){
    if( !parent_table ) return NULL;
    unsigned int idx;
    if( !parent_table->nodesNT.findName(str,&idx) ) return NULL;
    return getLastChildNodeAs( idx );
}

tdf_node* tdf_node::getNextChildNodeAs(tdf_node* ref){
    if( !ref ) return NULL;
    vector<tdf_node>::iterator i;
    unsigned int idx = ref->getIndex();
    if( !getChildNodePosAs(ref,&i) ) return NULL;
    i++;
    while( i < childNodes.end() ){
        if( (*i).getIndex() == idx ) return &(*i);
        i++;
    }
    return NULL;
}

tdf_node* tdf_node::getPrevChildNodeAs(tdf_node* ref){
    if( !ref ) return NULL;
    unsigned int idx = ref->getIndex();
    vector<tdf_node>::reverse_iterator i;
    if( !getChildNodePosAs(ref,&i) ) return NULL;
    i++;
    while( i < childNodes.rend() ){
        if( (*i).getIndex() == idx ) return &(*i);
        i++;
    }
    return NULL;
}

tdf_node* tdf_node::getChildNodeAsAt(unsigned int idx1, unsigned int idx2){
    unsigned int cnt = 0;
    for( vector<tdf_node>::iterator i = childNodes.begin(); i < childNodes.end(); i++ ){
        if( (*i).getIndex() == idx1 ){
            if( cnt == idx2 ){
                return &(*i);
            }
            cnt++;
        }
    }
    return NULL;
}
tdf_node* tdf_node::getChildNodeAsAt(string* str, unsigned int idx){
    if( !parent_table ) return NULL;
    unsigned int idx2;
    if( !parent_table->nodesNT.findName(str,&idx2) ) return NULL;
    return getChildNodeAsAt( idx2, idx );
}
tdf_node* tdf_node::getChildNodeAsAt(char* str, unsigned int idx){
    if( !parent_table ) return NULL;
    unsigned int idx2;
    if( !parent_table->nodesNT.findName(str,&idx2) ) return NULL;
    return getChildNodeAsAt( idx2, idx );
}

tdf_attribute* tdf_node::addAttrib(string* str){
        attrib.push_back( tdf_attribute( str, parent_table ) );
        return getLastAttrib();
}
tdf_attribute* tdf_node::addAttrib(char* str){
        attrib.push_back( tdf_attribute( str, parent_table ) );
        return getLastAttrib();
}

tdf_attribute* tdf_node::getAttrib(string* str){
    if( !parent_table ) return NULL;
    unsigned int idx;
    if( !parent_table->attributesNT.findName(str,&idx) ) return NULL;
    return getAttrib(idx);
}
tdf_attribute* tdf_node::getAttrib(char* str){
    if( !parent_table ) return NULL;
    unsigned int idx;
    if( !parent_table->attributesNT.findName(str,&idx) ) return NULL;
    return getAttrib(idx);
}
tdf_attribute* tdf_node::getAttrib(unsigned int idx){
    for( vector<tdf_attribute>::iterator i = attrib.begin(); i < attrib.end(); i++ ){
        if( (*i).getIndex() == idx ){
            return &(*i);
        }
    }
    return NULL;
}

bool tdf_node::hasAttrib(string* str){
    if( !parent_table ) return false;
    unsigned int idx;
    if( !parent_table->attributesNT.findName(str,&idx) ) return false;
    return hasAttrib(idx);
}
bool tdf_node::hasAttrib(char* str){
    if( !parent_table ) return false;
    unsigned int idx;
    if( !parent_table->attributesNT.findName(str,&idx) ) return false;
    return hasAttrib(idx);
}
bool tdf_node::hasAttrib(unsigned int idx){
    for( vector<tdf_attribute>::iterator i = attrib.begin(); i < attrib.end(); i++ ){
        if( (*i).getIndex() == idx ){
            return true;
        }
    }
    return false;
}

unsigned int tdf_node::countAttrib(){
    return attrib.size();
}
tdf_attribute* tdf_node::getFirstAttrib(){
    return &( *(attrib.begin()) );
}
tdf_attribute* tdf_node::getLastAttrib(){
    return &( *(attrib.rbegin()) );
}
tdf_attribute* tdf_node::getNextAttrib(tdf_attribute* ref){
    if( !ref ) return NULL;
    vector<tdf_attribute>::iterator  i;
    if( !getAttribPosAs(ref,&i) ) return NULL;
    i++;
    if( i >= attrib.end() ) return NULL;
    return &(*i);
}
tdf_attribute* tdf_node::getPrevAttrib(tdf_attribute* ref){
    if( !ref ) return NULL;
    vector<tdf_attribute>::reverse_iterator  i;
    if( !getAttribPosAs(ref,&i) ) return NULL;
    i++;
    if( i >= attrib.rend() ) return NULL;
    return &(*i);
}
tdf_attribute* tdf_node::getAttribAt(unsigned int idx){
    return &( attrib.at(idx) );
}

bool tdf_node::deleteChildNode(string* name,unsigned int pos){
    return deleteChildNode(getChildNodeAsAt(name,pos));
}
bool tdf_node::deleteChildNode(char* name,unsigned int pos){
    return deleteChildNode(getChildNodeAsAt(name,pos));
}
bool tdf_node::deleteChildNode(unsigned int idx,unsigned int pos){
    return deleteChildNode(getChildNodeAsAt(idx,pos));
}
bool tdf_node::deleteChildNode(tdf_node* nde){
    vector<tdf_node>::iterator it;
    if(!getChildNodePosAs(nde,&it)) return false;
    childNodes.erase(it);
    return true;
}
bool tdf_node::removeNode(){
    if( parent == this ) return false;
    return parent->deleteChildNode(this);
}
